"""
考试系统 - 考试相关模型
"""
from django.db import models
from django.contrib.auth import get_user_model
from django.utils import timezone
from django.core.validators import MinValueValidator, MaxValueValidator
import uuid

from apps.question_bank.models import QuestionBank, Question

User = get_user_model()


class Examination(models.Model):
    """
    考试
    定义考试内容和配置参数
    """
    class ExamType(models.TextChoices):
        NORMAL = 'normal', '常规考试'
        MIDTERM = 'midterm', '期中考试'
        FINAL = 'final', '期末考试'
        QUIZ = 'quiz', '测验考试'
        PRACTICE = 'practice', '练习考试'
        MOCK = 'mock', '模拟考试'

    class ExamStatus(models.TextChoices):
        DRAFT = 'draft', '草稿'
        PUBLISHED = 'published', '已发布'
        ONGOING = 'ongoing', '进行中'
        FINISHED = 'finished', '已结束'
        CANCELLED = 'cancelled', '已取消'

    class QuestionMode(models.TextChoices):
        FIXED = 'fixed', '固定题目'
        RANDOM = 'random', '随机题目'
        SMART = 'smart', '智能题目'

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    title = models.CharField(max_length=200, verbose_name='考试标题')
    description = models.TextField(blank=True, verbose_name='考试说明')

    # 考试类型和状态
    exam_type = models.CharField(
        max_length=20,
        choices=ExamType.choices,
        default=ExamType.NORMAL,
        verbose_name='考试类型'
    )
    status = models.CharField(
        max_length=20,
        choices=ExamStatus.choices,
        default=ExamStatus.DRAFT,
        verbose_name='考试状态'
    )

    # 考试时间
    start_time = models.DateTimeField(verbose_name='开始时间')
    end_time = models.DateTimeField(verbose_name='结束时间')
    duration = models.PositiveIntegerField(
        validators=[MinValueValidator(1), MaxValueValidator(1440)],  # 最长24小时
        verbose_name='考试时长(分钟)'
    )

    # 考试规则
    allow_late_join = models.BooleanField(default=False, verbose_name='允许迟到加入')
    auto_submit = models.BooleanField(default=True, verbose_name='自动提交试卷')
    show_score = models.BooleanField(default=False, verbose_name='显示分数')
    show_answer = models.BooleanField(default=False, verbose_name='显示答案')
    allow_retake = models.BooleanField(default=False, verbose_name='允许重考')

    # 题目设置
    question_mode = models.CharField(
        max_length=20,
        choices=QuestionMode.choices,
        default=QuestionMode.FIXED,
        verbose_name='题目模式'
    )

    # 关联题库
    question_bank = models.ForeignKey(
        QuestionBank,
        on_delete=models.PROTECT,
        related_name='examinations',
        verbose_name='题库'
    )

    # 分数设置
    total_score = models.DecimalField(
        max_digits=6,
        decimal_places=2,
        validators=[MinValueValidator(0)],
        verbose_name='总分'
    )
    pass_score = models.DecimalField(
        max_digits=6,
        decimal_places=2,
        validators=[MinValueValidator(0)],
        verbose_name='及格分'
    )

    # 创建者和监考人员
    creator = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='created_examinations',
        verbose_name='创建者'
    )
    supervisors = models.ManyToManyField(
        User,
        related_name='supervised_examinations',
        blank=True,
        verbose_name='监考人员'
    )

    # 时间戳
    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')

    class Meta:
        db_table = 'examinations'
        verbose_name = '考试'
        verbose_name_plural = '考试'
        indexes = [
            models.Index(fields=['creator', 'created_at']),
            models.Index(fields=['status', 'start_time']),
            models.Index(fields=['exam_type']),
            models.Index(fields=['question_bank']),
        ]
        ordering = ['-created_at']

    def __str__(self):
        return f"{self.title} ({self.get_exam_type_display()})"

    @property
    def is_active(self):
        """检查考试是否正在进行"""
        now = timezone.now()
        return self.start_time <= now <= self.end_time

    @property
    def is_finished(self):
        """检查考试是否已结束"""
        return timezone.now() > self.end_time

    @property
    def participant_count(self):
        """参与人数"""
        return self.exam_sessions.filter(status__in=['joined', 'in_progress', 'completed']).count()

    def can_participate(self, user):
        """检查用户是否可以参与考试"""
        if self.status != Examination.ExamStatus.PUBLISHED:
            return False, "考试未发布"

        if self.is_finished:
            return False, "考试已结束"

        # 检查是否已参与
        if self.exam_sessions.filter(user=user).exists():
            if not self.allow_retake:
                return False, "不允许重复考试"

        return True, "可以参与考试"


class ExaminationQuestion(models.Model):
    """
    考试题目
    定义考试与题目的关联关系
    """
    examination = models.ForeignKey(
        Examination,
        on_delete=models.CASCADE,
        related_name='questions',
        verbose_name='考试'
    )
    question = models.ForeignKey(
        Question,
        on_delete=models.CASCADE,
        related_name='examination_questions',
        verbose_name='题目'
    )
    question_order = models.PositiveIntegerField(verbose_name='题目顺序')
    custom_score = models.DecimalField(
        max_digits=5,
        decimal_places=2,
        null=True,
        blank=True,
        verbose_name='自定义分数'
    )
    is_required = models.BooleanField(default=True, verbose_name='是否必答')

    class Meta:
        db_table = 'examination_questions'
        verbose_name = '考试题目'
        verbose_name_plural = '考试题目'
        unique_together = ['examination', 'question']
        indexes = [
            models.Index(fields=['examination', 'question_order']),
            models.Index(fields=['question']),
        ]
        ordering = ['examination', 'question_order']

    def __str__(self):
        return f"{self.examination.title} - {self.question.title}"

    @property
    def effective_score(self):
        """有效分数"""
        return self.custom_score if self.custom_score is not None else self.question.points


class ExaminationSession(models.Model):
    """
    考试场次
    记录用户参与考试的具体信息
    """
    class SessionStatus(models.TextChoices):
        JOINED = 'joined', '已加入'
        IN_PROGRESS = 'in_progress', '进行中'
        COMPLETED = 'completed', '已完成'
        SUBMITTED = 'submitted', '已提交'
        TIMEOUT = 'timeout', '超时'
        DISCONNECTED = 'disconnected', '连接中断'
        CHEATING = 'cheating', '作弊'

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    examination = models.ForeignKey(
        Examination,
        on_delete=models.CASCADE,
        related_name='exam_sessions',
        verbose_name='考试'
    )
    user = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='exam_sessions',
        verbose_name='用户'
    )

    # 状态和时间
    status = models.CharField(
        max_length=20,
        choices=SessionStatus.choices,
        default=SessionStatus.JOINED,
        verbose_name='状态'
    )
    started_at = models.DateTimeField(null=True, blank=True, verbose_name='开始时间')
    finished_at = models.DateTimeField(null=True, blank=True, verbose_name='结束时间')
    time_spent = models.PositiveIntegerField(default=0, verbose_name='用时(秒)')

    # 成绩信息
    total_score = models.DecimalField(
        max_digits=6,
        decimal_places=2,
        null=True,
        blank=True,
        verbose_name='总分'
    )
    passed = models.BooleanField(null=True, blank=True, verbose_name='是否通过')

    # 详细成绩
    objective_score = models.DecimalField(
        max_digits=6,
        decimal_places=2,
        null=True,
        blank=True,
        verbose_name='客观题分数'
    )
    subjective_score = models.DecimalField(
        max_digits=6,
        decimal_places=2,
        null=True,
        blank=True,
        verbose_name='主观题分数'
    )

    # 监控信息
    ip_address = models.GenericIPAddressField(null=True, blank=True, verbose_name='IP地址')
    user_agent = models.TextField(blank=True, verbose_name='用户代理')
    cheating_detected = models.BooleanField(default=False, verbose_name='是否检测作弊')
    cheating_notes = models.TextField(blank=True, verbose_name='作弊说明')

    class Meta:
        db_table = 'examination_sessions'
        verbose_name = '考试场次'
        verbose_name_plural = '考试场次'
        unique_together = ['examination', 'user']
        indexes = [
            models.Index(fields=['examination', 'user']),
            models.Index(fields=['status']),
            models.Index(fields=['user', 'started_at']),
            models.Index(fields=['ip_address']),
        ]
        ordering = ['-started_at']

    def __str__(self):
        return f"{self.user.username} - {self.examination.title}"

    @property
    def is_in_progress(self):
        """检查是否正在进行"""
        return self.status == self.SessionStatus.IN_PROGRESS

    @property
    def remaining_time(self):
        """剩余时间(秒)"""
        if not self.started_at or self.status != self.SessionStatus.IN_PROGRESS:
            return 0

        elapsed = timezone.now() - self.started_at
        total_time = self.examination.duration * 60  # 分钟转秒
        remaining = total_time - elapsed.total_seconds()
        return max(0, remaining)

    def calculate_score(self):
        """计算成绩"""
        if not self.exam_answers.exists():
            return 0.0

        total_score = 0.0
        objective_score = 0.0
        subjective_score = 0.0

        for answer in self.exam_answers.all():
            question = answer.exam_question.question
            score = answer.get_score()
            total_score += score

            if question.type in ['choice', 'multiple_choice', 'true_false']:
                objective_score += score
            else:
                subjective_score += score

        self.total_score = total_score
        self.objective_score = objective_score
        self.subjective_score = subjective_score
        self.passed = total_score >= self.examination.pass_score

        return total_score


class ExaminationAnswer(models.Model):
    """
    考试答案
    记录用户对考试题目的答案
    """
    class AnswerStatus(models.TextChoices):
        PENDING = 'pending', '待评分'
        AUTO_GRADED = 'auto_graded', '自动评分'
        MANUALLY_GRADED = 'manually_graded', '人工评分'

    exam_session = models.ForeignKey(
        ExaminationSession,
        on_delete=models.CASCADE,
        related_name='exam_answers',
        verbose_name='考试场次'
    )
    exam_question = models.ForeignKey(
        ExaminationQuestion,
        on_delete=models.CASCADE,
        related_name='answers',
        verbose_name='考试题目'
    )

    # 答案内容
    answer = models.JSONField(default=dict, verbose_name='答案内容')
    text_answer = models.TextField(blank=True, verbose_name='文本答案')

    # 评分信息
    score = models.DecimalField(
        max_digits=5,
        decimal_places=2,
        null=True,
        blank=True,
        verbose_name='分数'
    )
    is_correct = models.BooleanField(null=True, blank=True, verbose_name='是否正确')
    status = models.CharField(
        max_length=20,
        choices=AnswerStatus.choices,
        default=AnswerStatus.PENDING,
        verbose_name='评分状态'
    )

    # 时间记录
    answered_at = models.DateTimeField(null=True, blank=True, verbose_name='答题时间')
    time_spent = models.PositiveIntegerField(default=0, verbose_name='答题用时(秒)')
    first_view_at = models.DateTimeField(null=True, blank=True, verbose_name='首次查看时间')
    view_count = models.PositiveIntegerField(default=0, verbose_name='查看次数')

    class Meta:
        db_table = 'examination_answers'
        verbose_name = '考试答案'
        verbose_name_plural = '考试答案'
        unique_together = ['exam_session', 'exam_question']
        indexes = [
            models.Index(fields=['exam_session', 'exam_question']),
            models.Index(fields=['status']),
            models.Index(fields=['answered_at']),
        ]
        ordering = ['exam_session', 'exam_question__question_order']

    def __str__(self):
        return f"{self.exam_session.user.username} - {self.exam_question.question.title}"

    def get_score(self):
        """获取分数"""
        if self.score is not None:
            return float(self.score)

        # 客观题自动评分
        if self.exam_question.question.type in ['choice', 'multiple_choice', 'true_false']:
            return self.auto_grade()

        return 0.0

    def auto_grade(self):
        """自动评分客观题"""
        question = self.exam_question.question

        if question.type in ['choice', 'true_false']:
            correct = self.answer.get('selected') == question.answer
            score = self.exam_question.effective_score if correct else 0
            self.is_correct = correct
            self.score = score
            self.status = self.AnswerStatus.AUTO_GRADED
            self.save(update_fields=['is_correct', 'score', 'status'])
            return float(score)

        elif question.type == 'multiple_choice':
            selected = set(self.answer.get('selected', []))
            correct = set(question.answer.split(','))

            if selected == correct:
                score = self.exam_question.effective_score
                self.is_correct = True
            elif selected.issubset(correct):
                # 部分正确给部分分数
                score = self.exam_question.effective_score * len(selected) / len(correct)
                self.is_correct = False
            else:
                score = 0
                self.is_correct = False

            self.score = score
            self.status = self.AnswerStatus.AUTO_GRADED
            self.save(update_fields=['is_correct', 'score', 'status'])
            return float(score)

        return 0.0


class ExaminationTemplate(models.Model):
    """
    考试模板
    用于快速创建标准化考试
    """
    name = models.CharField(max_length=200, verbose_name='模板名称')
    description = models.TextField(blank=True, verbose_name='模板描述')

    # 模板配置
    exam_type = models.CharField(
        max_length=20,
        choices=Examination.ExamType.choices,
        verbose_name='考试类型'
    )
    duration = models.PositiveIntegerField(verbose_name='考试时长(分钟)')
    question_mode = models.CharField(
        max_length=20,
        choices=Examination.QuestionMode.choices,
        verbose_name='题目模式'
    )

    # 题目配置
    question_config = models.JSONField(
        default=dict,
        help_text='题目配置，如：{type: count, score: value, difficulty: range}',
        verbose_name='题目配置'
    )

    # 分数配置
    total_score = models.DecimalField(
        max_digits=6,
        decimal_places=2,
        verbose_name='总分'
    )
    pass_percentage = models.DecimalField(
        max_digits=3,
        decimal_places=2,
        validators=[MinValueValidator(0), MaxValueValidator(100)],
        verbose_name='及格百分比'
    )

    # 考试规则
    settings = models.JSONField(
        default=dict,
        help_text='考试规则配置',
        verbose_name='考试规则'
    )

    # 创建者
    creator = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='exam_templates',
        verbose_name='创建者'
    )

    # 使用统计
    usage_count = models.PositiveIntegerField(default=0, verbose_name='使用次数')

    created_at = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')

    class Meta:
        db_table = 'examination_templates'
        verbose_name = '考试模板'
        verbose_name_plural = '考试模板'
        indexes = [
            models.Index(fields=['creator', 'created_at']),
            models.Index(fields=['exam_type']),
        ]

    def __str__(self):
        return self.name

    def get_pass_score(self):
        """获取及格分数"""
        return self.total_score * self.pass_percentage / 100


class ExamStatistics(models.Model):
    """
    考试统计
    记录考试统计数据和分析
    """
    examination = models.OneToOneField(
        Examination,
        on_delete=models.CASCADE,
        related_name='statistics',
        verbose_name='考试'
    )

    # 基本统计
    total_participants = models.PositiveIntegerField(default=0, verbose_name='总参与人数')
    completed_count = models.PositiveIntegerField(default=0, verbose_name='完成人数')
    passed_count = models.PositiveIntegerField(default=0, verbose_name='通过人数')

    # 分数统计
    average_score = models.DecimalField(
        max_digits=6,
        decimal_places=2,
        null=True,
        blank=True,
        verbose_name='平均分'
    )
    highest_score = models.DecimalField(
        max_digits=6,
        decimal_places=2,
        null=True,
        blank=True,
        verbose_name='最高分'
    )
    lowest_score = models.DecimalField(
        max_digits=6,
        decimal_places=2,
        null=True,
        blank=True,
        verbose_name='最低分'
    )

    # 分数分布
    score_distribution = models.JSONField(
        default=dict,
        help_text='分数分布统计',
        verbose_name='分数分布'
    )

    # 题目分析
    question_analysis = models.JSONField(
        default=dict,
        help_text='题目分析数据',
        verbose_name='题目分析'
    )

    # 时间分析
    time_analysis = models.JSONField(
        default=dict,
        help_text='时间分析数据',
        verbose_name='时间分析'
    )

    updated_at = models.DateTimeField(auto_now=True, verbose_name='更新时间')

    class Meta:
        db_table = 'exam_statistics'
        verbose_name = '考试统计'
        verbose_name_plural = '考试统计'

    def __str__(self):
        return f"{self.examination.title} - 统计数据"

    def update_statistics(self):
        """更新统计数据"""
        sessions = self.examination.exam_sessions.filter(
            status=ExaminationSession.SessionStatus.COMPLETED
        )

        if not sessions.exists():
            return

        # 基本统计
        self.total_participants = self.examination.exam_sessions.count()
        self.completed_count = sessions.count()
        self.passed_count = sessions.filter(passed=True).count()

        # 分数统计
        scores = [float(session.total_score) for session in sessions if session.total_score]
        if scores:
            self.average_score = sum(scores) / len(scores)
            self.highest_score = max(scores)
            self.lowest_score = min(scores)

        # 计算分数分布
        self.score_distribution = self._calculate_score_distribution(scores)

        # 题目分析
        self.question_analysis = self._analyze_questions(sessions)

        # 时间分析
        self.time_analysis = self._analyze_time(sessions)

        self.save()

    def _calculate_score_distribution(self, scores):
        """计算分数分布"""
        if not scores:
            return {}

        total_score = float(self.examination.total_score)
        ranges = [
            (0, 60), (60, 70), (70, 80), (80, 90), (90, 100)
        ]

        distribution = {}
        for i, (min_val, max_val) in enumerate(ranges):
            if total_score > 0:
                actual_min = total_score * min_val / 100
                actual_max = total_score * max_val / 100
                count = len([s for s in scores if actual_min <= s < actual_max])
                distribution[f"{min_val}-{max_val}"] = count

        return distribution

    def _analyze_questions(self, sessions):
        """题目分析"""
        analysis = {}

        for exam_question in self.examination.questions.all():
            question_key = str(exam_question.question.id)
            answers = [answer for session in sessions for answer in session.exam_answers.filter(exam_question=exam_question)]

            if answers:
                correct_count = len([a for a in answers if a.is_correct])
                total_count = len(answers)
                avg_score = sum([float(a.score or 0) for a in answers]) / total_count

                analysis[question_key] = {
                    'question_title': exam_question.question.title,
                    'total_attempts': total_count,
                    'correct_count': correct_count,
                    'accuracy_rate': correct_count / total_count if total_count > 0 else 0,
                    'average_score': float(avg_score),
                    'full_marks': len([a for a in answers if float(a.score or 0) >= float(exam_question.effective_score)])
                }

        return analysis

    def _analyze_time(self, sessions):
        """时间分析"""
        if not sessions.exists():
            return {}

        time_data = [session.time_spent for session in sessions if session.time_spent]
        if not time_data:
            return {}

        return {
            'average_time': sum(time_data) / len(time_data),
            'max_time': max(time_data),
            'min_time': min(time_data),
            'time_distribution': {
                'fast': len([t for t in time_data if t < self.examination.duration * 30]),  # 快速完成
                'normal': len([t for t in time_data if self.examination.duration * 30 <= t < self.examination.duration * 45]),
                'slow': len([t for t in time_data if t >= self.examination.duration * 45])
            }
        }